package com.xjrsoft.module.iot.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.StrUtil;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.enums.IotProtocolEnum;
import com.xjrsoft.common.exception.MyException;
import com.xjrsoft.common.model.result.R;
import com.xjrsoft.common.mqtt.OpcUaClientService;
import com.xjrsoft.common.utils.IotUtil;
import com.xjrsoft.common.utils.RedisUtil;
import com.xjrsoft.module.iot.dto.AddIotLinkDto;
import com.xjrsoft.module.iot.dto.UpdateIotLinkDto;
import com.xjrsoft.module.iot.entity.IotDic;
import com.xjrsoft.module.iot.entity.IotLink;
import com.xjrsoft.module.iot.mapper.IotLinkMapper;
import com.xjrsoft.module.iot.service.IIotLinkService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author tzx
 * @since 2024-04-10
 */
@Service
@Slf4j
@AllArgsConstructor
public class IotLinkServiceImpl extends ServiceImpl<IotLinkMapper, IotLink> implements IIotLinkService {

    private final RedisUtil redisUtil;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addIotLink(AddIotLinkDto dto) {

        IotLink link = BeanUtil.toBean(dto, IotLink.class);

        save(link);

        if (dto.getProtocolType() == IotProtocolEnum.MQTT.getCode()) {
            IotUtil.initMqttServer(link);
        }
        else {
            IotUtil.initOpcuaServer(link);
        }

        return true;
    }

    @Override
    public boolean updateIotLink(UpdateIotLinkDto dto) {
        IotLink link = BeanUtil.toBean(dto, IotLink.class);
        updateById(link);

        if (dto.getProtocolType() == IotProtocolEnum.MQTT.getCode()) {
            MqttClient mqttClient = IotUtil.cacheMqttClientMap.get(link.getId());

            try {
                mqttClient.disconnect();
            } catch (MqttException e) {
                throw new MyException("修改链接出现问题！");
            }
            IotUtil.cacheMqttClientMap.remove(link.getId());
            IotUtil.initMqttServer(link);
        }
        else {
            OpcUaClient opcUaClient = IotUtil.cacheOpcUaClientMap.get(link.getId());

            try {
                opcUaClient.disconnect().get();
            } catch (Exception e) {
                throw new MyException("修改链接出现问题！");
            }

            IotUtil.cacheOpcUaClientMap.remove(link.getId());
            IotUtil.initOpcuaServer(link);
        }
        return true;
    }

    @Override
    public boolean testConnect(AddIotLinkDto dto) {

        if (dto.getProtocolType() == IotProtocolEnum.MQTT.getCode()) {
            return initIotServer(BeanUtil.toBean(dto,IotLink.class));
        }
        else {
            return initOpcuaServer(BeanUtil.toBean(dto, IotLink.class));
        }

    }

    private boolean initIotServer(IotLink iotLink) {
        MqttClient mqttClient = null;

        try {
            mqttClient = new MqttClient(iotLink.getHostUrl(), iotLink.getClientId() + LocalDateTime.now(),new MemoryPersistence());
            MqttConnectOptions options = new MqttConnectOptions();

            if(StrUtil.isNotEmpty(iotLink.getUsername()) && StrUtil.isNotEmpty(iotLink.getPassword())){
                options.setUserName(iotLink.getUsername());
                options.setPassword(iotLink.getPassword().toCharArray());
            }

            options.setAutomaticReconnect(true);
            options.setCleanSession(true);
            options.setConnectionTimeout(10);

            options.setKeepAliveInterval(20);
//            options.setWill(iotLink.getTopic(), "offline".getBytes(), 0, false);
            mqttClient.setTimeToWait(5000);
            mqttClient.connect(options);


            log.info("mqtt host:{} clientId:{} 已经连接上", iotLink.getHostUrl(), iotLink.getClientId());
            return true;
        } catch (MqttException e) {

            e.printStackTrace();
            return false;
        }
        finally {
            if(mqttClient!=null){
                try {
                    mqttClient.disconnect();
                }
                catch (MqttException e){
                    e.printStackTrace();
                }
            }
        }

    }



    /**
     * 构建opcUa 连接
     * @param iotLink
     */
    private boolean initOpcuaServer(IotLink iotLink) {
        OpcUaClient opcUaClient = null;
        try {
            OpcUaClientService opcUaClientService = new OpcUaClientService();

            // 与OPC UA服务端建立连接，并返回客户端实例
            opcUaClient = opcUaClientService.connectOpcUaServer(iotLink.getHostUrl(), iotLink.getUsername(), iotLink.getPassword());

            return true;
        }
        catch (Exception e){
            e.printStackTrace();
            return false;
        }
        finally {
            if(opcUaClient!=null){
                try {
                    opcUaClient.disconnect().get();
                }
                catch (Exception e){
                    e.printStackTrace();
                }
            }
        }

    }

}
